package com.pactera.asmp.server.service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.pactera.asmp.server.common.constants.ResultCode;
import com.pactera.asmp.server.common.exception.CustomException;
import com.pactera.asmp.server.dao.CameraInfoMapper;
import com.pactera.asmp.server.dao.LaboratoryInfoMapper;
import com.pactera.asmp.server.dao.ProjectMapper;
import com.pactera.asmp.server.dao.UserMapper;
import com.pactera.asmp.server.entity.*;
import com.pactera.asmp.server.pojo.ProjectInfo;
import com.pactera.asmp.server.pojo.User;
import com.pactera.asmp.server.utils.PageDataResult;

@Service
public class LaboratoryInfoServiceImpl implements ILaboratoryInfoService {

    private static final Logger logger = LoggerFactory.getLogger(LaboratoryInfoServiceImpl.class);

    @Autowired
    private LaboratoryInfoMapper laboratoryInfoMapper;

    @Autowired
    private CameraInfoMapper cameraInfoMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ProjectMapper projectMapper;

    @Override
    public PageDataResult select(LaboratoryInfoSearchDTO laboratoryInfoSearchDTO) {
        logger.info(JSONObject.toJSONString(laboratoryInfoSearchDTO));
        PageDataResult pageDataResult = new PageDataResult();
        PageHelper.startPage(laboratoryInfoSearchDTO.getPage(), laboratoryInfoSearchDTO.getLimit());

        LaboratoryInfoExample example = new LaboratoryInfoExample();
        LaboratoryInfoExample.Criteria criteria = example.createCriteria();
//        criteria.andStatusEqualTo(0);a
        if(StringUtils.isNotEmpty(laboratoryInfoSearchDTO.getLabName())) {
            criteria.andLabNameLike("%" + laboratoryInfoSearchDTO.getLabName() + "%");
        }
        if(null != laboratoryInfoSearchDTO.getProjectId()) {
            criteria.andProjectIdEqualTo(laboratoryInfoSearchDTO.getProjectId());
        }
        List<LaboratoryInfo> laboratoryInfos = laboratoryInfoMapper.selectByExample(example);
        if(CollectionUtils.isEmpty(laboratoryInfos)) {
            pageDataResult.setTotals(0);
            pageDataResult.setList(Lists.newArrayList());
            return pageDataResult;
        }
        List<Integer> labIds = laboratoryInfos.stream().map(LaboratoryInfo::getId).distinct().collect(Collectors.toList());

        // 获取摄像头信息
        List<CameraInfo> cameraInfos = getCameraInfos(labIds);
        Map<Integer, List<CameraInfo>> cameraMap = Maps.newHashMap();
        if(CollectionUtils.isNotEmpty(cameraInfos)) {
            cameraMap.putAll(cameraInfos.stream().collect(Collectors.groupingBy(CameraInfo::getLabId)));
        }

        // 获取创建人与更新人信息
        List<Integer> userIds = Lists.newArrayList();
        Map<Integer, String> userNameMap = Maps.newHashMap();
        List<Integer> createUserIds = laboratoryInfos.stream().filter(v -> null != v.getCreateUid()).map(LaboratoryInfo::getCreateUid).collect(Collectors.toList());
        List<Integer> updateUserIds = laboratoryInfos.stream().filter(v -> null != v.getUpdateUid()).map(LaboratoryInfo::getUpdateUid).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(createUserIds)) userIds.addAll(createUserIds);
        if(CollectionUtils.isNotEmpty(updateUserIds)) userIds.addAll(updateUserIds);
        if(CollectionUtils.isNotEmpty(userIds)) {
            List<User> users = userMapper.selectByPrimaryKeys(userIds.stream().distinct().collect(Collectors.toList()));
            if(CollectionUtils.isNotEmpty(users)) {
                userNameMap.putAll(users.stream().collect(Collectors.toMap(User::getId, User::getUsername)));
            }
        }

        // 获取项目信息
        List<ProjectInfo> projectInfos = projectMapper.getProjectName(laboratoryInfos.stream().map(LaboratoryInfo::getProjectId).distinct().collect(Collectors.toList()));
        Map<Integer, String> projectNameMap = Maps.newHashMap();
        if(CollectionUtils.isNotEmpty(projectInfos)) {
            projectNameMap.putAll(projectInfos.stream().collect(Collectors.toMap(ProjectInfo::getId, ProjectInfo::getProjectName)));
        }

        List<LaboratoryInfoDTO> list = laboratoryInfos.stream().map(info -> {
            LaboratoryInfoDTO laboratoryInfoDTO = new LaboratoryInfoDTO();
            BeanUtils.copyProperties(info, laboratoryInfoDTO);
            List<CameraInfo> cameralist = cameraMap.getOrDefault(laboratoryInfoDTO.getId(), Lists.newArrayList());
            laboratoryInfoDTO.setCameras(cameralist);
            if(null != info.getCreateUid()) {
                laboratoryInfoDTO.setCreateUser(userNameMap.get(info.getCreateUid()));
            }
            if(null != info.getUpdateUid()) {
                laboratoryInfoDTO.setUpdateUser(userNameMap.get(info.getUpdateUid()));
            }
            laboratoryInfoDTO.setProjectName(projectNameMap.get(info.getProjectId()));
            return laboratoryInfoDTO;
        }).collect(Collectors.toList());
        PageInfo<LaboratoryInfoDTO> pageInfo = new PageInfo<>(list);
        pageDataResult.setTotals(Long.valueOf(pageInfo.getTotal()).intValue());
        pageDataResult.setList(list);
        return pageDataResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer insert(LaboratoryInfoDTO laboratoryInfoDTO) {
        logger.info(JSONObject.toJSONString(laboratoryInfoDTO));
        User currUser = (User) SecurityUtils.getSubject().getPrincipal();
        if (currUser == null) throw new CustomException(ResultCode.PERMISSION_EXPIRE);

        if(!checkNameExist(null, laboratoryInfoDTO.getLabName(), laboratoryInfoDTO.getProjectId()))
            throw new CustomException(ResultCode.BUSINESS_LABNAME_EXISTED);

        LaboratoryInfo laboratoryInfo = new LaboratoryInfo();
        BeanUtils.copyProperties(laboratoryInfoDTO, laboratoryInfo);
        laboratoryInfo.setCreateTime(LocalDateTime.now());
        laboratoryInfo.setCreateUid(currUser.getId());
        int cnt = laboratoryInfoMapper.insert(laboratoryInfo);
        if(cnt < 1) {
            throw new CustomException(ResultCode.FAIL);
        }
        if(CollectionUtils.isNotEmpty(laboratoryInfoDTO.getCameraIds())) {
            for(Integer cameraId : laboratoryInfoDTO.getCameraIds()) {
                CameraInfo cameraInfo = new CameraInfo();
                cameraInfo.setId(cameraId);
                cameraInfo.setLabId(laboratoryInfo.getId());
                cameraInfo.setServiceStatus(0);
                cameraInfoMapper.updateByPrimaryKeySelective(cameraInfo);
            }
        }
        return laboratoryInfo.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(LaboratoryInfoDTO laboratoryInfoDTO) {
        logger.info(JSONObject.toJSONString(laboratoryInfoDTO));
        User currUser = (User) SecurityUtils.getSubject().getPrincipal();
        if (currUser == null) throw new CustomException(ResultCode.PERMISSION_EXPIRE);

        if(!checkNameExist(laboratoryInfoDTO.getId(), laboratoryInfoDTO.getLabName(), laboratoryInfoDTO.getProjectId()))
            throw new CustomException(ResultCode.BUSINESS_LABNAME_EXISTED);

        LaboratoryInfo laboratoryInfo = laboratoryInfoMapper.selectByPrimaryKey(laboratoryInfoDTO.getId());
        if(null == laboratoryInfo || null == laboratoryInfo.getId()) {
            throw new CustomException(ResultCode.BUSINESS_LAB_NOT_EXISTED);
        }
        laboratoryInfo.setLabName(laboratoryInfoDTO.getLabName());
        laboratoryInfo.setStatus(laboratoryInfoDTO.getStatus());
        laboratoryInfo.setProjectId(laboratoryInfoDTO.getProjectId());
        laboratoryInfo.setUpdateTime(LocalDateTime.now());
        laboratoryInfo.setUpdateUid(currUser.getId());
        int cnt = laboratoryInfoMapper.updateByPrimaryKey(laboratoryInfo);
        if(cnt < 1) {
            return false;
        }
        List<CameraInfo> cameraInfos = getCameraInfos(Lists.newArrayList(laboratoryInfoDTO.getId()));
        if(CollectionUtils.isNotEmpty(cameraInfos)) {

            if(CollectionUtils.isNotEmpty(laboratoryInfoDTO.getCameraIds())) {
                cameraInfos = cameraInfos.stream().filter(
                        cameraInfo -> !laboratoryInfoDTO.getCameraIds().contains(cameraInfo.getId())).collect(Collectors.toList());
            }
            if(CollectionUtils.isNotEmpty(cameraInfos)) {
                CameraInfo cameraInfo = new CameraInfo();
                cameraInfo.setLabId(0);
                cameraInfo.setServiceStatus(1);
                CameraInfoExample cameraInfoExample = new CameraInfoExample();
                cameraInfoExample.createCriteria()
                    .andIdIn(cameraInfos.stream().map(CameraInfo::getId).collect(Collectors.toList()));
                cameraInfoMapper.updateByExampleSelective(cameraInfo, cameraInfoExample);
            }
        }

        if(CollectionUtils.isNotEmpty(laboratoryInfoDTO.getCameraIds())) {
            CameraInfo cameraInfo = new CameraInfo();
            cameraInfo.setLabId(laboratoryInfoDTO.getId());
            cameraInfo.setServiceStatus(0);
            CameraInfoExample cameraInfoExample = new CameraInfoExample();
            cameraInfoExample.createCriteria()
                .andIdIn(laboratoryInfoDTO.getCameraIds());
            cameraInfoMapper.updateByExampleSelective(cameraInfo, cameraInfoExample);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(Integer labId) {
        LaboratoryInfo laboratoryInfo = laboratoryInfoMapper.selectByPrimaryKey(labId);
        if(null == laboratoryInfo || null == laboratoryInfo.getId()) {
            throw new CustomException(ResultCode.BUSINESS_LAB_NOT_EXISTED);
        }
        if(0 == laboratoryInfo.getStatus()) {
            throw new CustomException(ResultCode.BUSINESS_LAB_CANNOT_DELETE);
        }
        int cnt = laboratoryInfoMapper.deleteByPrimaryKey(labId);
        if(cnt < 1) {
            return false;
        }
        CameraInfo cameraInfo = new CameraInfo();
        cameraInfo.setLabId(0);
        cameraInfo.setServiceStatus(1);
        CameraInfoExample cameraInfoExample = new CameraInfoExample();
        cameraInfoExample.createCriteria().andLabIdEqualTo(labId);
        cameraInfoMapper.updateByExampleSelective(cameraInfo, cameraInfoExample);
        return true;
    }

    /**
     * 校验一个项目下是否有重复的实验室名称
     * 
     * @param id
     * @param labName
     * @param projectId
     * @return
     */
    private boolean checkNameExist(Integer id, String labName, Integer projectId) {
        LaboratoryInfoExample example = new LaboratoryInfoExample();
        LaboratoryInfoExample.Criteria criteria = example.createCriteria();
        if(null != id) {
            criteria.andIdNotEqualTo(id);
        }
        criteria.andLabNameEqualTo(labName);
        criteria.andProjectIdEqualTo(projectId);
        return CollectionUtils.isEmpty(laboratoryInfoMapper.selectByExample(example));
    }

    /**
     * 获取实验室下的摄像头
     * 
     * @param labIds
     * @return
     */
    private List<CameraInfo> getCameraInfos(List<Integer> labIds) {
        CameraInfoExample cameraInfoExample = new CameraInfoExample();
        cameraInfoExample.createCriteria().andLabIdIn(labIds);
        return cameraInfoMapper.selectByExample(cameraInfoExample);
    }
}
